using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class CubicSpline {
	#region properties
	//point[0] is the start point of the spline, point[1] the first control point, 
	// point[2] the second control point and point[3] the end point
	private Vector3[] _points = new Vector3[4];
	
		//Only the nodes on the track are of interest to the rasterizer,
	//so we don't return the control points
	public Vector3[] points
	{
		get
		{
			return new Vector3[] {_points[0], _points[3]};
		}
	}
	#endregion
	
	#region constructors
	//The public constructor, which makes a CubicSpline section out of two SplineControlPoints
	public CubicSpline(SplineControlPoint start, SplineControlPoint end)
	{
		_points[0] = start.location;
		_points[1] = start.location+start.direction*start.weights[1];
		
		_points[2] = end.location-end.direction*end.weights[0];
		_points[3] = end.location;
	}
	
	//This constructor is used internally by the subdivide function
	private CubicSpline(Vector3[] points)
	{
		_points = points;
	}
	#endregion
	
	#region subdivision functions
	//Recursively subdivides the track until the length is smaller than the specified length
	//See also http://www.ams.org/samplings/feature-column/fcarc-bezier#2
	public List<CubicSpline> subdivide(int lmax)
	{
		//Subdivide the lines between the 4 points that make up the spline
		Vector3 p01 = Vector3.Lerp(_points[0], _points[1], 0.5f);
		Vector3 p12 = Vector3.Lerp(_points[1], _points[2], 0.5f);
		Vector3 p23 = Vector3.Lerp(_points[2], _points[3], 0.5f);
		
		//Subdivide the lines between the points found that way
		Vector3 p012 = Vector3.Lerp(p01, p12, 0.5f);
		Vector3 p123 = Vector3.Lerp(p12, p23, 0.5f);
		
		//Finaly, the midpoint of our spline is halfway between the two points obtained that way.
		Vector3 p0123 = Vector3.Lerp(p012, p123, 0.5f);
		
		float length = Vector3.Distance(_points[0], p0123);
		
		//We split the spline in two
		CubicSpline frontSpline = new CubicSpline(new Vector3[] {_points[0], p01, p012, p0123});
		CubicSpline backSpline = new CubicSpline(new Vector3[] {p0123, p123, p23, _points[3]});
		
		List<CubicSpline> newSplines = new List<CubicSpline>();
		
		//Return the two splines if the section is short enough
		if (length < lmax)
		{
			newSplines.Add(frontSpline);
			newSplines.Add(backSpline);
		}
		//Or recur on those splines if it's not.
		else
		{
			newSplines.AddRange(frontSpline.subdivide(lmax));
			newSplines.AddRange(backSpline.subdivide(lmax));
		}
		
		return newSplines;
	}
	#endregion
}